/*******************************************************************************
* 
*    Copyright(C) 2018 BX All rights reserved.
* 
* File        : driver.c
* Author      : BX
* Version     : V1.00
* Date        : 2018-1-1
* Description : 驱动代码
* Chip        : HC32L136
* History     : V1.00, 2018-1-1, bx, first version

* Disclaimer  :
*   本程序所有权归作者所有。
*   本程序仅用于演示或实现特定产品的功能，任何修改或其它目的的应用均不作保证，
*   未经作者同意不得将本程序的全部或部分用于商业目的。
*******************************************************************************/
#include "driver.h"

DRIVER driver;

// delay us @4M
void delay_us(uint16_t us)
{
#ifdef __ICCARM__
    while(us > 2)
    {
        us -= 2; 
        nop();nop();
    }
#endif

#ifdef __CC_ARM
    uint16_t i;

    for(i=0; i<us; i+=2)
    {
        nop();nop();nop();	
    }
#endif	
}

// delay ms @1M
void delay_ms(uint16_t ms)
{
    uint16_t i;

    for(i=0; i<ms; i++)
    {
        delay_us(250);
    }
}


/*******************************************************************************
 * 时钟初始化
*******************************************************************************/
void clock_switch(void)
{
    // RCH切换频率步骤如下：先切换到RCL，加载频率校准值，再切换到RCH
  
    // RCH时钟的频率切换，需要先将时钟切换到RCL
    Sysctrl_SetRCLTrim(SysctrlRclFreq32768);
    Sysctrl_ClkSourceEnable(SysctrlClkRCL, TRUE);
    Sysctrl_SysClkSwitch(SysctrlClkRCL);
    
    // 加载目标频率的RCH的TRIM值
    //Sysctrl_SetRCHTrim(SysctrlRchFreq4MHz);
    Sysctrl_SetRCHTrim(SysctrlRchFreq8MHz);
    //Sysctrl_SetRCHTrim(SysctrlRchFreq16MHz); 
    //Sysctrl_SetRCHTrim(SysctrlRchFreq22_12MHz);
    //Sysctrl_SetRCHTrim(SysctrlRchFreq24MHz);
    
    // 切换到RCH
    Sysctrl_ClkSourceEnable(SysctrlClkRCH, TRUE);
    Sysctrl_SysClkSwitch(SysctrlClkRCH);
    
    // 根据需要关闭RCL
    Sysctrl_ClkSourceEnable(SysctrlClkRCL, FALSE);
}

void clock_init(void)
{
    // 时钟默认为RCH4M，具体见system_hc32l13x.c的SystemInit()

    //clock_switch();
  
    // 分频设置
    //Sysctrl_SetHCLKDiv(SysctrlHclkDiv2);  // HCLK=SysCLK/2
    //Sysctrl_SetPCLKDiv(SysctrlPclkDiv2);  // PCLK=HCLK/2
}


/*******************************************************************************
 * 端口初始化
*******************************************************************************/
void port_init(void)
{
    // 端口配置结构
    stc_gpio_cfg_t pstcGpioCfg;
    
    // 使能GPIO时钟
    Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio, TRUE);
	
		// 初始化IO口
    Gpio_SetIO(GpioPortA, GpioPin7);										// POWER-OFF/RUN-LED/RST
		Gpio_SetIO(GpioPortA, GpioPin1);
		Gpio_SetIO(GpioPortA, GpioPin2);
		Gpio_ClrIO(GpioPortA, GpioPin3);
	
		Gpio_SetIO(GpioPortB, GpioPin9);										// TEST/CS1/CS2
		Gpio_SetIO(GpioPortD, GpioPin4);
		Gpio_SetIO(GpioPortB, GpioPin7);
	
		Gpio_SetIO(GpioPortD, GpioPin5);										// CLK/SDI/RST
		Gpio_SetIO(GpioPortA, GpioPin4);
		Gpio_SetIO(GpioPortA, GpioPin6);
	
		pstcGpioCfg.enDir = GpioDirOut;                     // 输出
    pstcGpioCfg.enDrv = GpioDrvH;                       // 高驱动
    pstcGpioCfg.enPu  = GpioPuDisable;                  // 禁用上拉             
    pstcGpioCfg.enPd  = GpioPdDisable;                  // 禁用下拉                
    pstcGpioCfg.enOD  = GpioOdDisable;                  // 禁用开漏
    
    // LED配置    
    Gpio_Init(GpioPortA, GpioPin1, &pstcGpioCfg);
    Gpio_Init(GpioPortA, GpioPin2, &pstcGpioCfg);
    Gpio_Init(GpioPortA, GpioPin3, &pstcGpioCfg); 
    Gpio_Init(GpioPortA, GpioPin7, &pstcGpioCfg); 
		// TEST/CS1/CS2 控制口配置 
	  Gpio_Init(GpioPortB, GpioPin9, &pstcGpioCfg); 
	  Gpio_Init(GpioPortD, GpioPin4, &pstcGpioCfg); 
	  Gpio_Init(GpioPortB, GpioPin7, &pstcGpioCfg); 
		// CLK/SDI/RST 控制口配置 
	  Gpio_Init(GpioPortD, GpioPin5, &pstcGpioCfg); 
	  Gpio_Init(GpioPortA, GpioPin4, &pstcGpioCfg); 
	  Gpio_Init(GpioPortA, GpioPin6, &pstcGpioCfg); 

    // KEY配置
    pstcGpioCfg.enDir = GpioDirIn;                      // 输入
    pstcGpioCfg.enDrv = GpioDrvH;                       // 高驱动
    pstcGpioCfg.enPu 	= GpioPuDisable;                  // 禁用上拉             
    pstcGpioCfg.enPd 	= GpioPdDisable;                  // 禁用下拉                
    pstcGpioCfg.enOD 	= GpioOdDisable;                  // 禁用开漏
    Gpio_Init(GpioPortC, GpioPin12, &pstcGpioCfg);
    Gpio_Init(GpioPortC, GpioPin11, &pstcGpioCfg);
    Gpio_Init(GpioPortC, GpioPin10, &pstcGpioCfg);
    Gpio_Init(GpioPortA, GpioPin15, &pstcGpioCfg);
    // SDO
		Gpio_Init(GpioPortA, GpioPin5, 	&pstcGpioCfg);
		// ID4-ID1 输入口配置
		Gpio_Init(GpioPortB, GpioPin5, 	&pstcGpioCfg);
		Gpio_Init(GpioPortB, GpioPin4, 	&pstcGpioCfg);
		Gpio_Init(GpioPortB, GpioPin3, 	&pstcGpioCfg);
		Gpio_Init(GpioPortD, GpioPin2, 	&pstcGpioCfg);
   
    
    // KEY配置    
    // 端口中断
    //使能端口系统中断
    EnableNvic(PORTC_IRQn, IrqLevel3, TRUE);
    EnableNvic(PORTA_IRQn, IrqLevel3, TRUE);
    
    //配置为上升下降沿中断
    Gpio_EnableIrq(GpioPortC, GpioPin12, GpioIrqFalling);
    Gpio_EnableIrq(GpioPortC, GpioPin12, GpioIrqRising); 

    Gpio_EnableIrq(GpioPortC, GpioPin11, GpioIrqFalling);
    Gpio_EnableIrq(GpioPortC, GpioPin11, GpioIrqRising);
    Gpio_EnableIrq(GpioPortC, GpioPin10, GpioIrqFalling);
    Gpio_EnableIrq(GpioPortC, GpioPin10, GpioIrqRising);
    Gpio_EnableIrq(GpioPortA, GpioPin15, GpioIrqFalling);
    Gpio_EnableIrq(GpioPortA, GpioPin15, GpioIrqRising);
 
}



// GPIO中断
void PortA_IRQHandler(void)
{
    if(TRUE == Gpio_GetIrqStatus(GpioPortA, GpioPin15))
    {
        Gpio_ClearIrq(GpioPortA, GpioPin15);
        
        if(Gpio_GetInputIO(GpioPortA, GpioPin15))
        {

        }
        else
        {

        }  
    }
}

void PortC_IRQHandler(void)
{
    if(TRUE == Gpio_GetIrqStatus(GpioPortC, GpioPin12))
    {
        Gpio_ClearIrq(GpioPortC, GpioPin12);
        
        if(Gpio_GetInputIO(GpioPortC, GpioPin12))
        {

        }
        else
        {

        }  
    }
    
    if(TRUE == Gpio_GetIrqStatus(GpioPortC, GpioPin11))
    {
        Gpio_ClearIrq(GpioPortC, GpioPin11);
        
        if(Gpio_GetInputIO(GpioPortC, GpioPin11))
        {

        }
        else
        {

        }  
    }
    
    if(TRUE == Gpio_GetIrqStatus(GpioPortC, GpioPin10))
    {
        Gpio_ClearIrq(GpioPortC, GpioPin10);
        
        if(Gpio_GetInputIO(GpioPortC, GpioPin10))
        {

        }
        else
        {

        }  
    }
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/*******************************************************************************
 * RTC中断服务函数
 ******************************************************************************/
void Rtc_IRQHandler(void)
{
    if(Rtc_GetPridItStatus() == TRUE)
    {
        driver.rtc_int = 1;
        
        Rtc_ClearPrdfItStatus();             //清除中断标志位
    }
}

void rtc_init(void)
{
    stc_rtc_initstruct_t RtcInitStruct;
   
    //使能RCL
    Sysctrl_SetRCLTrim(SysctrlRclFreq32768);    
    Sysctrl_ClkSourceEnable(SysctrlClkRCL, TRUE);
    
    Sysctrl_SetPeripheralGate(SysctrlPeripheralRtc, TRUE);//RTC模块时钟打开
    
    RtcInitStruct.rtcAmpm = RtcPm;                       //24小时制
    RtcInitStruct.rtcClksrc = RtcClkRcl;                 //外部低速时钟
    RtcInitStruct.rtcPrdsel.rtcPrdsel = RtcPrds;         //周期中断类型PRDS
    RtcInitStruct.rtcPrdsel.rtcPrds = Rtc1S;             //周期中断时间间隔 1秒
   
    RtcInitStruct.rtcTime.u8Second = 0x55;               //配置RTC时间
    RtcInitStruct.rtcTime.u8Minute = 0x01;
    RtcInitStruct.rtcTime.u8Hour   = 0x10;
    RtcInitStruct.rtcTime.u8Day    = 0x17;
    RtcInitStruct.rtcTime.u8DayOfWeek = 0x04;
    RtcInitStruct.rtcTime.u8Month  = 0x04;
    RtcInitStruct.rtcTime.u8Year   = 0x19;
    RtcInitStruct.rtcCompen = RtcCompenDisable;           // 使能时钟误差补偿
    RtcInitStruct.rtcCompValue = 0;                      //补偿值  根据实际情况进行补偿
    Rtc_Init(&RtcInitStruct);
    
    Rtc_AlmIeCmd(FALSE);                                  //使能闹钟中断
    
    EnableNvic(RTC_IRQn, IrqLevel3, TRUE);               //使能RTC中断向量
    Rtc_Cmd(TRUE);                                       //使能RTC开始计数
}

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////



////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/*******************************************************************************
 * Lpt中断服务函数
 ******************************************************************************/
void LpTim_IRQHandler(void)
{
    if (TRUE == Lptim_GetItStatus(M0P_LPTIMER))
    {
        Lptim_ClrItStatus(M0P_LPTIMER);//清除LPTimer的中断标志位
        
        driver.lpt_int = 1;
    }
}

void lpt_init(void)
{
    stc_lptim_cfg_t    stcLptCfg;
    DDL_ZERO_STRUCT(stcLptCfg);
    
    //使能RCL
    Sysctrl_SetRCLTrim(SysctrlRclFreq32768);    
    Sysctrl_ClkSourceEnable(SysctrlClkRCL, TRUE);
    
    ///< 使能LPTIM0 外设时钟
    Sysctrl_SetPeripheralGate(SysctrlPeripheralLpTim, TRUE);

    stcLptCfg.enGate   = LptimGateLow;
    stcLptCfg.enGatep  = LptimGatePLow;
    stcLptCfg.enTcksel = LptimRcl;
    stcLptCfg.enTogen  = LptimTogEnHigh;    // 翻转输出使能
    stcLptCfg.enCt     = LptimTimerFun;     //计数器功能
    stcLptCfg.enMd     = LptimMode2;        //工作模式为模式2：自动重装载16位计数器/定时器
    stcLptCfg.u16Arr   = 32767;             //预装载寄存器值
    Lptim_Init(M0P_LPTIMER, &stcLptCfg);

    Lptim_ClrItStatus(M0P_LPTIMER);   			//清除中断标志位
    Lptim_ConfIt(M0P_LPTIMER, TRUE);  			//允许LPTIMER中断
    EnableNvic(LPTIM_IRQn, IrqLevel3, TRUE);
    
    Lptim_Cmd(M0P_LPTIMER, TRUE);
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////



////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void lcd_init(void)
{
    stc_lcd_cfg_t LcdInitStruct;
    stc_lcd_segcom_t LcdSegCom;

    //使能RCL
    Sysctrl_SetRCLTrim(SysctrlRclFreq32768);    
    Sysctrl_ClkSourceEnable(SysctrlClkRCL, TRUE);

    Sysctrl_SetPeripheralGate(SysctrlPeripheralLcd,TRUE);   ///< 开启LCD时钟

    LcdSegCom.u32Seg0_31 = 0xFFFFC000;                              ///< 配置LCD_POEN0寄存器 开启SEG0~SEG7
    LcdSegCom.stc_seg32_51_com0_8_t.seg32_51_com0_8 = 0xffffffff;   ///< 初始化LCD_POEN1寄存器 全部关闭输出端口
    LcdSegCom.stc_seg32_51_com0_8_t.segcom_bit.Com0_3 = 0;          ///< 使能COM0~COM3
    LcdSegCom.stc_seg32_51_com0_8_t.segcom_bit.Mux = 1;             ///< Mux=0,Seg32_35=0,BSEL=1表示:选择外部电容工作模式，内部电阻断路
    LcdSegCom.stc_seg32_51_com0_8_t.segcom_bit.Seg32_35 = 0xF;
    Lcd_SetSegCom(&LcdSegCom);                                      ///< LCD COMSEG端口配置

    LcdInitStruct.LcdBiasSrc = LcdInResLowPower;                   ///< 电容分压模式，需要外部电路配合
    LcdInitStruct.LcdDuty = LcdDuty4;                              ///< 1/4duty
    LcdInitStruct.LcdBias = LcdBias3;                              ///< 1/3 BIAS
    LcdInitStruct.LcdCpClk = LcdClk2k;                             ///< 电压泵时钟频率选择2kHz
    LcdInitStruct.LcdScanClk = LcdClk256hz;                        ///< LCD扫描频率选择128Hz
    LcdInitStruct.LcdMode = LcdMode0;                              ///< 选择模式0
    LcdInitStruct.LcdClkSrc = LcdRCL;                              ///< LCD时钟选择RCL
    LcdInitStruct.LcdEn   = LcdEnable;                             ///< 使能LCD模块
    Lcd_Init(&LcdInitStruct);
  
    Lcd_SetContrast(1);

    
    // 液晶口配置成输出
    // COM
    Gpio_SetAnalogMode(GpioPortA, GpioPin9);  //COM0
    Gpio_SetAnalogMode(GpioPortA, GpioPin10); //COM1
    Gpio_SetAnalogMode(GpioPortA, GpioPin11); //COM2
    Gpio_SetAnalogMode(GpioPortA, GpioPin12); //COM3   
    
    // SEG
    Gpio_SetAnalogMode(GpioPortA, GpioPin8);  
    Gpio_SetAnalogMode(GpioPortC, GpioPin9);  
    Gpio_SetAnalogMode(GpioPortC, GpioPin8);  
    Gpio_SetAnalogMode(GpioPortC, GpioPin7); 
    
    Gpio_SetAnalogMode(GpioPortC, GpioPin6);  
    Gpio_SetAnalogMode(GpioPortB, GpioPin15);  
    Gpio_SetAnalogMode(GpioPortB, GpioPin14);  
    Gpio_SetAnalogMode(GpioPortB, GpioPin13);  
    
    Gpio_SetAnalogMode(GpioPortB, GpioPin12);  
    Gpio_SetAnalogMode(GpioPortB, GpioPin11);  
    Gpio_SetAnalogMode(GpioPortB, GpioPin10);  
    Gpio_SetAnalogMode(GpioPortB, GpioPin2);  
    
    Gpio_SetAnalogMode(GpioPortB, GpioPin1);  
    Gpio_SetAnalogMode(GpioPortB, GpioPin0); 

    Lcd_FullDisp();
}


const uint8_t lcd_code[] = 
{
	// 0 - 9
	0x5F, 0x06, 0x6B, 0x2F, 0x36, 0x3D, 0x7D, 0x07, 0x7F, 0x3F, 
	// A - F
	0x77, 0x7C, 0x59, 0x6E, 0x79, 0x71,
	// - N _ Y  U
	0x20, 0x57, 0x00, 0x76, 0x5e
};


void lcd_clear(void)
{
    Lcd_ClearDisp();
}

void lcd_enable(void)
{
    M0P_LCD->CR0_f.EN = 1;              // lcd off
}

void lcd_disable(void)
{
    M0P_LCD->CR0_f.EN = 0;              // lcd on
}

void lcd_write_code(uint8_t i, uint8_t c)
{
    uint32_t s;
		//	c:	bit7  bit6  bit5  bit4  bit3  bit2  bit1  bit0	转换为：    
		//	s:	seg3  seg2  seg1  seg0  seg7  seg6  seg5  seg4
    switch(i)
    {
			case 0:
						s = ((c&0x0F)<<8)|((c>>3)&0x0E);
						M0P_LCD->RAM0 |= s;				//	bit0-3 -> seg8-11
						break;
			case 1:
						s = (c&0x70)<<21;
						M0P_LCD->RAM0 |= s;				//	bit4-6 -> seg25-27
						s = c&0x0F;
						M0P_LCD->RAM1 |= s;				//	bit0-3 -> seg0-3
						break;
			case 2:
						s = (c&0x70)<<5;
						M0P_LCD->RAM1 |= s;				//	bit4-6 -> seg9-11
						s = (c&0x0F)<<16;
						M0P_LCD->RAM1 |= s;				//	seg0-3 -> seg16-19
						break;
			case 3:
						s = (c&0x70)<<21;
						M0P_LCD->RAM1 |= s;				//	bit4-6 -> seg25-27
						s = c&0x0F;
						M0P_LCD->RAM2 |= s;				//	bit0-3 -> seg0-3
						break;
			case 4:
						s = (c&0x70)<<5;
						M0P_LCD->RAM2 |= s;				//	bit4-6 -> seg9-11
						s = (c&0x0F)<<16;
						M0P_LCD->RAM2 |= s;				//	seg0-3 -> seg16-19
						break;
			default:
					break;
    }      
}


void lcd_write_char(uint8_t i, uint8_t d)
{
    lcd_write_code(i, lcd_code[d]);
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
